{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "# data_folder = os.path.join(os.path.expanduser(\"~\"), \"data\", \"datasets\")\n",
    "data_folder = \"C:/Users/Anthony Dave/Desktop/Complier/Learning-Data-Mining-with-Python-Second-Edition-master/Chapter05\"\n",
    "data_filename = os.path.join(data_folder, \"ad.data\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [],
   "source": [
    "def convert_number(x):\n",
    "    try:\n",
    "        return float(x)\n",
    "    except ValueError:\n",
    "        return np.nan"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [],
   "source": [
    "converters = {}\n",
    "for i in range(1558):\n",
    "    converters[i] = convert_number"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [],
   "source": [
    "converters[1558] = lambda x: 1 if x.strip() == \"ad.\" else 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [],
   "source": [
    "ads = pd.read_csv(data_filename, header=None, converters=converters)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>0</th>\n",
       "      <th>1</th>\n",
       "      <th>2</th>\n",
       "      <th>3</th>\n",
       "      <th>4</th>\n",
       "      <th>5</th>\n",
       "      <th>6</th>\n",
       "      <th>7</th>\n",
       "      <th>8</th>\n",
       "      <th>9</th>\n",
       "      <th>...</th>\n",
       "      <th>1549</th>\n",
       "      <th>1550</th>\n",
       "      <th>1551</th>\n",
       "      <th>1552</th>\n",
       "      <th>1553</th>\n",
       "      <th>1554</th>\n",
       "      <th>1555</th>\n",
       "      <th>1556</th>\n",
       "      <th>1557</th>\n",
       "      <th>1558</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>125.0</td>\n",
       "      <td>125.0</td>\n",
       "      <td>1.0000</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>...</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>57.0</td>\n",
       "      <td>468.0</td>\n",
       "      <td>8.2105</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>...</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>33.0</td>\n",
       "      <td>230.0</td>\n",
       "      <td>6.9696</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>...</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>60.0</td>\n",
       "      <td>468.0</td>\n",
       "      <td>7.8000</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>...</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>60.0</td>\n",
       "      <td>468.0</td>\n",
       "      <td>7.8000</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>...</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>5 rows × 1559 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "    0      1       2     3     4     5     6     7     8     9     ...  1549  \\\n",
       "0  125.0  125.0  1.0000   1.0   0.0   0.0   0.0   0.0   0.0   0.0  ...   0.0   \n",
       "1   57.0  468.0  8.2105   1.0   0.0   0.0   0.0   0.0   0.0   0.0  ...   0.0   \n",
       "2   33.0  230.0  6.9696   1.0   0.0   0.0   0.0   0.0   0.0   0.0  ...   0.0   \n",
       "3   60.0  468.0  7.8000   1.0   0.0   0.0   0.0   0.0   0.0   0.0  ...   0.0   \n",
       "4   60.0  468.0  7.8000   1.0   0.0   0.0   0.0   0.0   0.0   0.0  ...   0.0   \n",
       "\n",
       "   1550  1551  1552  1553  1554  1555  1556  1557  1558  \n",
       "0   0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0     1  \n",
       "1   0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0     1  \n",
       "2   0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0     1  \n",
       "3   0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0     1  \n",
       "4   0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0     1  \n",
       "\n",
       "[5 rows x 1559 columns]"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ads.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [],
   "source": [
    "ads.dropna(inplace=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [],
   "source": [
    "X = ads.drop(1558, axis=1).values\n",
    "y = ads[1558]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.decomposition import PCA\n",
    "pca = PCA(n_components=5)\n",
    "Xd = pca.fit_transform(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Xd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.854, 0.145, 0.001, 0.   , 0.   ])"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.set_printoptions(precision=3, suppress=True)\n",
    "pca.explained_variance_ratio_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.tree import DecisionTreeClassifier\n",
    "from sklearn.model_selection import cross_val_score\n",
    "clf = DecisionTreeClassifier(random_state=14)\n",
    "scores_reduced = cross_val_score(clf, Xd, y, scoring='accuracy')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.956, 0.934, 0.958, 0.917, 0.917])"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "scores_reduced"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "from matplotlib import pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [],
   "source": [
    "classes = set(y)\n",
    "colors = ['red', 'green']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0       1\n",
       "1       1\n",
       "2       1\n",
       "3       1\n",
       "4       1\n",
       "       ..\n",
       "3273    0\n",
       "3274    0\n",
       "3275    0\n",
       "3276    0\n",
       "3278    0\n",
       "Name: 1558, Length: 2359, dtype: int64"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{0, 1}"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "classes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [],
   "source": [
    "import seaborn as sns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 720x576 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10,8))\n",
    "sns.set_style(\"whitegrid\")\n",
    "for cur_class, color in zip(classes, colors):\n",
    "    mask = (y == cur_class).values\n",
    "    plt.scatter(Xd[mask,0], Xd[mask,1], marker='o', color=color, label=int(cur_class))\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Custom Transformer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.base import TransformerMixin\n",
    "from sklearn.utils import as_float_array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MeanDiscrete(TransformerMixin): # API\n",
    "    def fit(self, X, y=None):\n",
    "        X = as_float_array(X)\n",
    "        self.mean = X.mean(axis=0)\n",
    "        return self\n",
    "\n",
    "    def transform(self, X, y=None):\n",
    "        X = as_float_array(X)\n",
    "        assert X.shape[1] == self.mean.shape[0]\n",
    "        return X > self.mean"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [],
   "source": [
    "mean_discrete = MeanDiscrete()\n",
    "# X_mean = mean_discrete.fit_transform(X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Mean Discrete performance: 0.939\n"
     ]
    }
   ],
   "source": [
    "from sklearn.pipeline import Pipeline\n",
    "pipeline = Pipeline([('mean_discrete', MeanDiscrete()), ('classifier', DecisionTreeClassifier(random_state=14))])\n",
    "scores_mean_discrete = cross_val_score(pipeline, X, y, scoring='accuracy')\n",
    "print(\"Mean Discrete performance: {0:.3f}\".format(scores_mean_discrete.mean()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [],
   "source": [
    "from numpy.testing import assert_array_equal\n",
    "def test_meandiscrete():\n",
    "    X_test = np.array([[0, 2],\n",
    "                      [3,5],\n",
    "                      [6, 8],\n",
    "                      [9, 11],\n",
    "                      [12, 14],\n",
    "                      [15, 17],\n",
    "                      [18, 20],\n",
    "                      [21, 23],\n",
    "                      [24, 26],\n",
    "                      [27, 29]])\n",
    "    mean_discrete = MeanDiscrete()\n",
    "    mean_discrete.fit(X_test)\n",
    "    assert_array_equal(mean_discrete.mean, np.array([13.5, 15.5]))\n",
    "    X_transformed = mean_discrete.transform(X_test)\n",
    "    X_expected = np.array([[0, 0],\n",
    "                          [0, 0],\n",
    "                          [0, 0],\n",
    "                          [0, 0],\n",
    "                          [0, 0],\n",
    "                          [1, 1],\n",
    "                          [1, 1],\n",
    "                          [1, 1],\n",
    "                          [1, 1],\n",
    "                          [1, 1]])\n",
    "    assert_array_equal(X_transformed,X_expected)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [],
   "source": [
    "# test_meandiscrete()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Mean Discrete performance: 0.939\n"
     ]
    }
   ],
   "source": [
    "from sklearn.pipeline import Pipeline\n",
    "pipeline = Pipeline([('mean_discrete', MeanDiscrete()),\n",
    "                    ('classifier', DecisionTreeClassifier(random_state=14))])\n",
    "scores_mean_discrete = cross_val_score(pipeline, X, y, scoring='accuracy')\n",
    "print(\"Mean Discrete performance: {0:.3f}\".format(scores_mean_discrete.mean()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
